\documentclass[11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[spanish]{babel}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage[a4paper,left=3cm,right=3cm]{geometry}
\usepackage{graphicx}

\title{TPE: Arquitectura De Computadoras \\
        Modo protegido con GRUB}

\author{Tomás Alvarez \and Carlos Sessa \and María Belén Aguilera}
\date{22 de Octubre del 2007}

\begin{document}
\maketitle
\centerline{Instituto Tecnológico de Buenos Aires}
\newpage

\tableofcontents

\newpage

\section{Introducción}
\subsection{Objetivo}
Realizar un programa que muestre algunas de las características del Modo protegido de los microprocesadores de Intel.

\subsection{Planificación}
\begin{itemize}
 \item Implementar una estructura de file descriptor y su manager para una mejor organización.
 \item Escribir las primitivas usando los prototipos del sistema operativo Linux.
 \item Driver de video por medio de fd.
 \item Driver de teclado por medio de fd.
 \item Libc con los prototipos originales.
 \item Shell.
 \item lsusb.
 \item Otras funcionalidades.
 \item Testeo.
\end{itemize}

\newpage

\section{Desarrollo}
\subsection{Testeo}
Para testear nuestras implementaciones usamos:
\begin{itemize}
 \item Qemu.
 \item Bochs.
 \item Vmware.
\end{itemize}

Notamos que las funcionalidades tenían distintas salidas según la máquina virtual donde lo probáramos.
Por lo general, si no funcionaba en un sistema lo testeábamos en una máquina real para asegurarnos de su corrección.

\subsection{File Descriptor}
Se ideó crear la abstracción de file descriptors para que read y write tengan el mismo prototipo.
Por falta de tiempo no se llegó a implementar pero se quería usar los file descriptors para:
\begin{itemize}
 \item Redirigir \textit{stderr}, \textit{stdin}, \textit{stdout}.
 \item Implementar una especie de procesador de texto que se guarde en memoria.
\end{itemize}

\subsection{Read y Write}
Para implementar read y write primero leimos los prototipos de las versiones de Linux.

\subsection{Driver de Video}
Se implementaron las funcionalidades típicas de la pantalla. Se usó una estructura que debe inicializar el kernel para especificar ancho, alto, etc.
Por falta de tiempo no se pudo implementar pero se quería cambiar el alto de la pantalla durante el iniciado de "módulos" poniendo una imagen en ascii en la parte superior.

\subsection{Driver de Teclado}
El Driver de teclado funciona tanto con mapeo en español como en inglés. Se tuvo en cuenta prender los leds que indican \textit{capsLock}, \textit{numLock}, \textit{scrollLock}.

\subsection{LibC}
Se discutió mucho si stdarg.h debería incluirse o no. Terminamos deciendo que por más que se encontraba en la libc, es la que usa el precompilador para que el programador pueda usar argumentos variables.
No se pensó desde un principio que funciones de la libc íbamos a agregar sino que a medida que las necesitábamos, se implementaban.

\subsection{Shell}
Aparte de las funcionalidades típicas, se implementó la posibilidad de cambiar el skin cambiando las propiedades del video.
Se pensó en la posibilidad de implementar "pipes" haciendo que la salida del "proceso1" sea la entrada del "proceso2", pero se decidió implementar en la materia que le sigue a esta aprovechando el multiproceso.

\subsection{lsusb}
Para realizar el lsusb tuvimos que hacer un lspci detectando los dispositivos pci conectados.
Sólo implementamos driver para \textit{UHCI}.
Armamos una lista de dispositivos pci que se correspondían con host controller de UHCI y se busca entre los dispositivos pci conectados si existe alguno dentro de esa lista.
No se llegó a implementar mostrar en pantalla el device string del dispositivo USB pero por medio de los puertos del host controller sabemos si hay un usb conectado o no.

\subsection{Otras funcionalidades}
Para probar que el sistema operativo funcionaba correctamente agregamos otras funcionalidades.
Algunas de ellas fueron:
\begin{itemize}
 \item Random
 \item Restart
 \item Shutdown
 \item date
\end{itemize}

Notamos que la idea de implementar todos los prototipos igual a Linux nos facilitó mucho la implementación.
Por lo general durante el desarrollo de la mismas un integrante del grupo las implementaba en linux y después la probaba en nuestro sistema operativo sin problemas.

\newpage

\section{Segunda Entrega}
Para la segunda entrega se pidió:
\begin{itemize}
 \item Corrección del lspci.
 \item Funciones OUT e IN para prender leds del teclado sean realizadas por INT 80h.
 \item Informe de cómo debería haber sido implementado el listado de dispositivos USB.
 \end{itemize}

\subsection{lspci}
\subsubsection{Problemática}
Para realizar el listado de PCI, se realizaba lo siguiente:
\begin{itemize}
 \item Triple for anidado con Bus Number, Device Number y Function Number.
 \item Se leía la estructura del PCI.
 \item Si el VendorID era distinto a 0xFFFF se imprimía.
 \end{itemize}

Esta solución funcionaba bien en las máquinas virtuales, pero cuando lo probamos en una máquina real mostraba los mismos dispositivos con distintos números de funciones.

\subsubsection{Solución}
Para solucionarlo agregamos dos variables más dentro de la función para guardar los últimos vendorID y deviceID dentro del ciclo de Function Number. Si se encuentra un dispositivo PCI pero ya se había impreso en pantalla, no se muestra. De esta manera muestra sólo un dispositivo por Bus Number y Device Number.


\subsection{OUT e IN para leds del teclado}
\subsubsection{Problemática}
Para prender los leds del teclado se implementó una función en asm que realiza out/in al puerto 60h.
No existe problemática de funcionalidad pero como se está accediendo a hardware hay que hacerlo por medio de una interrupción.

\subsubsection{Solución}
Se implementó OUT e IN como system call llamando a INT 80h.


\subsection{Listado de dispositivos USB}
\subsubsection{Introducción}
Para realizar el listado de USB nos basamos en la información expuesta en la wiki de osdev. (http://wiki.osdev.org/USB)

Los pasos a seguir, son los siguientes:
\begin{itemize}
 \item Encontrar el tipo de Host Controller y su I/O address usando el bus PCI.
 \item Resetear el Host.
 \item Resetear el Puerto.
 \item Revisar el estado del puerto para detectar la inserción de dispositivos.
 \item Habilitar el Puerto.
 \item Obtener el Device Descriptor del dispositivo.
 \end{itemize}


\subsubsection{Tipo de Host Controller}
Investigando descubrimos que existen tres tipos de Host Controllers.
\begin{itemize}
 \item OHCI (Open Host Controller Interface)
 \item UHCI (Universal Host Controller Interface)
 \item EHCI (Extended Host Controller Interface)
 \end{itemize}

Optamos por implementar el driver para UHCI porque fue el que encontramos en todas las PCs que teníamos para testear y las máquinas virtuales emulaban un UHCI cuando le agregamos compatibilidad con USB.
Para detectar el Host Controller de la PC se realiza probing de PCI buscando aquellos que se encuentren en nuestra lista de uhciDevices.\\
\textbf{NOTA:} La lista fue creada con un CSV bajado de: http://www.pcidatabase.com/ y al probar en máquinas nuevas, no detecta bien el Host Controller. Esto se debe a que el CSV usado no está actualizado.

\subsubsection{I/O address}
Para obtener la IO adress, usamos el método mencionado en la wiki de osDev acerca de PCI.\\
\textit{''...BARs are used to hold memory addresses used by the device, for example the DMA address. It can also hold I/O ports. To distinguish between them, you can check if the lowest bit is 1. If it is, the lower word represents the I/O port. Also don't forget to zero the lowest bit...''}\\
Una vez que se detecta el Host Controller se leen los BARs en busca del I/O Port.


\subsubsection{Resetear el Host Controller}
Para este punto nos basamos en el código fuente del driver para UHCI del kernel de Linux. (
http://www.mjmwired.net/kernel/Documentation/usb/uhci.txt) \\
El primer problema al migrar el código de linux a nuestro sistema operativo era la existencia de una función \textit{uhci\_wait\_ms}. Hasta este punto no teníamos noción del tiempo dentro de nuestro sistema y para no lograr este función con un bucle largo implementamos la biblioteca time.\\
Los pasos para resetear el Host Controller son los siguientes:
\begin{itemize}
 \item Se manda un USBCMD\_GRESET (Global reset) a la dirección base + USBCMD (Command register).
 \item Se esperan \textbf{mínimo} 50ms.
 \item Se manda un 0 a la dirección base + USBCMD (Command register).
  \item Se esperan \textbf{mínimo} 10ms.
 \end{itemize}

Una vez hecho el global reset, hay que resetear el Host Controller. Esto fuerza a obtener una nuevo notificación de los dispositivos ya conectados gracias al desconectado virtual.
\begin{itemize}
 \item Se manda un USBCMD\_HCRESET (Host reset) a la dirección base + USBCMD (Command register).
 \item Se escribe un cero en la dirección base + USBFRNUM (6).
 \item Se escribe la dirección de memoria del frameList en la dirección base + USBFLBASEADD (8).
 \end{itemize}
\textbf{NOTA:} En el driver de Linux se llama a kalloc para obtener memoria para el frameList. Teóricamente ese espacio es accedido por el Host Controller y tiene que estar en el rango de direcciones que los dispositivos PCI pueden acceder por DMA. En nuestro caso lo hicimos con un vector dentro de la estructura que representa el dispositivo UHCI.

\subsubsection{Resetear el puerto y habilitarlo}
Para resetear el puerto se realiza lo siguiente:
\begin{itemize}
 \item Se resetea el puerto con USBPORTSC\_PR (Port Reset).
 \item Se esperan \textbf{mínimo} 10ms.
 \item Se limpia el bit de USBPORTSC\_PR (Port Reset).
 \item Se habilita el puerto con USBPORTSC\_PE (Port Enable Change).
 \item Se esperan \textbf{mínimo} 10ms.
 \end{itemize}

Una vez hecho esto el Host Controller puede detectar si se conectaron dispositivos al bus. Se armó una función de debug que lo que hace es leer lo que hay en el puerto 1 y 2 de la dirección base + USBPORTSC1(16) y USBPORTSC2 (18). Como el valor default es 0x80 si al leer encontramos algo distinto es que hay un dispositivo conectado.\\
\textbf{NOTA:} Esto último funcionó en la máquina virtual corriendo sobre vmware, pero lamentablemente no en máquinas reales.

\subsubsection{Obtener el Device Descriptor del dispositivo}
La especificación de USB define cuatro tipos de transferencias:
\begin{itemize}
 \item Transferencias de Control.
 \item Transferencias de Interrupción.
 \item Transferencias Isocrónicas.
 \item Transferencias Bulk.
 \end{itemize}

Para obtener el Device Descriptor hay que hacer una transferencia de Control. Esta consta de 3 partes que se explicarán a continuación.\\

\textbf{Etapa de Configuración:}\\
La etapa de configuración es la que se encarga de enviar el pedido. Esto se realizará en tres paquetes.\\

\textit{Primer paquete:}\\
El host envia un token de configuración diciéndole a la función que el próximo paquete va a ser de configuración. El campo de la dirección va a ser la del dispositivo. El Endpoint debe ser cero.

\textit{Segundo paquete:}\\
Se genera el paquete DATA0. Este contendrá uno de los ocho ''Standard Device Requests'', en este caso \textit{GET\_DESCRIPTOR}.

\textit{Tercer paquete:}\\
La función de USB hace el ACK que el paquete de configuración se recibió correctamente.
\begin{center}
    \includegraphics[width=12cm]{./scripts/usb1.png}\\
    \textit{Figura1:} Etapa de Configuración.\\
\end{center}

Una vez hecho esto, el dispositivo USB decodifica los 8 bytes recibidos e interpreta qué es. El dispositivo intentará enviar el Device Descriptor.

\textbf{Etapa de envio de Información:}\\
La etapa de configuración determinó la cantidad de información a ser transferida y como excede el tamaño máximo de paquete se realizarán múltiples INs. \\
El Host envia un IN, diciéndole al dispositivo que está listo para recibir. Como el tamaño máximo de paquete es 8 bytes, se debe cortar. Los paquetes serán de 8bytes, excepto el último. El host hace un ack con cada paquete de información que le llega.
\begin{center}
    \includegraphics[width=12cm]{./scripts/usb1.png}\\
    \textit{Figura2:} Etapa de envio de Información.\\
\end{center}

Una vez que se termina de enviar el device descriptor comienza la etapa de estado.

\textbf{Etapa de estado:}\\
Si las transacciones fueron exitosas el Host envia un paquete de tamaño cero. Luego el dispositivo envia un paquete de tamaño cero como ack.
\begin{center}
    \includegraphics[width=12cm]{./scripts/usb1.png}\\
    \textit{Figura3:} Etapa de estado.\\
\end{center}

\subsubsection{Conclusión}
En primer lugar nos pareció que la Guía de Diseño que ofrece Intel para UHCI no está muy bien documentada. Nos llamó mucho la atención que la mayoría de los sistemas operativos hechos como hobby dentro de la comunidad de osdev no cuentan con la implementación de USB. Los únicos códigos de implementación de UHCI que encontramos fueron:

\begin{itemize}
 \item asm: http://forum.osdev.org/viewtopic.php?f=1\&t=18312\&start=15
 \item Pascal: USB4DOS: http://www.filesearching.com/cgi-bin/s?q=usb4dos.zip\&l=en\&e=on
 \item C: Kernel de Linux.
 \end{itemize}

Cómo el código de asm y de Pascal no estaban muy bien documentados, optamos por basarnos en el driver de UHCI para el Kernel de Linux. Nunca habíamos intentado leer el Kernel y aprovechamos esta oportunidad para hacerlo. El hecho de tener acceso al Kernel de Linux aceleró mucho el desarrollo del driver.  Notamos que el código está muy bien comentado, y es relativamente fácil de seguir pero por otro lado toma tiempo entenderlo.\\
Tuvimos muchos inconvenientes a la hora de debuggear. El hecho de que las máquinas virtuales usadas no sean muy fieles con respecto a una máquina real nos dificultó el desarrollo.



\subsubsection{Bibliografía utilizada para este punto}
\begin{itemize}
 \item Wiki de osDev: http://wiki.osdev.org/
 \item Foro de osDev: http://forum.osdev.org/
 \item USB in a NutShell: http://www.beyondlogic.org/usbnutshell/
 \item The Universal Host Controller Interface (UHCI) Design Guide.
 \item UHCI driver del Kernel: http://www.mjmwired.net/kernel/Documentation/usb/uhci.txt
 \end{itemize}

\newpage

\section{Manual del Usuario}
\subsection{Comandos}
La lista de comandos es la siguiente:
\begin{itemize}
    \item \textit{help}
    \item \textit{clear}
    \item \textit{shell}
    \item \textit{set\_keyblayout}
    \item \textit{lsusb}
    \item \textit{lspci}
    \item \textit{date}
    \item \textit{ls}
    \item \textit{random}
    \item \textit{skin}
    \item \textit{shutdown}
    \item \textit{tf}
    \item \textit{restart}
    \item \textit{exit}
\end{itemize}

En las siguientes secciones se explicará el funcionamiento y uso.

\newpage

\subsubsection{help}
\begin{verbatim}
NAME
    help - Imprime la ayuda de un comando en particular.

SYNOPSIS
    help comando

DESCRIPTION
    help imprime el string de ayuda dentro del vector de comandos de shell.c.
    Si no encuentra el comando muestra mensaje de error.

EXAMPLES
    help help
        Muestra el help del comando help.
\end{verbatim}

\subsubsection{clear}
\begin{verbatim}
NAME
    clear - Limpia la pantalla.

SYNOPSIS
    clear

DESCRIPTION
    clear limpia la pantalla llamando a clearScreen() dentro de video.c.

EXAMPLES
    clear
        Limpia la pantalla.
\end{verbatim}

\subsubsection{shell}
\begin{verbatim}
NAME
    shell - Inicia una nueva shell.

SYNOPSIS
    shell

DESCRIPTION
    shell crea una nueva shell.

EXAMPLES
    shell
        Crea una nueva shell.
\end{verbatim}

\subsubsection{set\_keyblayout}
\begin{verbatim}
NAME
    set_keyblayout - Cambia el mapeo del teclado al elegido.

SYNOPSIS
    set_keyblayout layout

DESCRIPTION
    set_keyblayout cambia el mapeo del teclado.

EXAMPLES
    set_keyblayout english
        Cambia el mapeo a ingles.
\end{verbatim}

\subsubsection{lsusb}
\begin{verbatim}
NAME
    lsusb - Lista dispositivos usb.

SYNOPSIS
    lsusb

DESCRIPTION
    lsusb busca dentro de los dispositivos PCI aquellos que sean UHCI
		y lista el dispositivo conectado al mismo si es existe.

EXAMPLES
    lsusb
        Lista si hay conectado un dispositivo usb.
\end{verbatim}

\subsubsection{lspci}
\begin{verbatim}
NAME
    lspci - Lista dispositivos pci.

SYNOPSIS
    lspci

DESCRIPTION
    lspci busca dispositivos PCI e imprime su VendorID y DeviceID.

EXAMPLES
    lspci
        Lista dispositivos pci detectados.
\end{verbatim}

\subsubsection{date}
\begin{verbatim}
NAME
    date - Fecha del sistema.

SYNOPSIS
    date

DESCRIPTION
    date lee datos del CMOS e imprime la fecha.

EXAMPLES
    date
        Imprime la fecha.
\end{verbatim}

\subsubsection{ls}
\begin{verbatim}
NAME
    ls - lista los comandos del sistema operativo.

SYNOPSIS
    ls

DESCRIPTION
    ls lee los comandos existentes dentro del shell y los imprime en pantalla.

EXAMPLES
    ls
        Lista comandos del sistema.
\end{verbatim}

\subsubsection{random}
\begin{verbatim}
NAME
    random - Imprime un numero pseudoaleatorio.

SYNOPSIS
    random

DESCRIPTION
    random usa una variable no inicializada y la multiplica por el dia y los segundos.

EXAMPLES
    random 5
        Imprime un numero random entre 0 y 5.
\end{verbatim}

\subsubsection{skin}
\begin{verbatim}
NAME
    skin - Cambia el skin de la shell.

SYNOPSIS
    skin skinName

DESCRIPTION
    skin cambia los atributos de los caracteres a imprimir en pantalla.

EXAMPLES
    skin rosita
        Cambia el skin a rosita. Texto negro y fondo rosa.
\end{verbatim}

\subsubsection{shutdown}
\begin{verbatim}
NAME
    shutdown - Apaga la pc.

SYNOPSIS
    shutdown

DESCRIPTION
    shutdown utiliza ACPI. La pc debe tener habilitada esa funcionalidad.

EXAMPLES
    shutdown
        Apaga la pc.
\end{verbatim}

\subsubsection{tf}
\begin{verbatim}
NAME
    tf - Genera un triple fault.

SYNOPSIS
    tf

DESCRIPTION
    tf genera un triple fault para apagar la pc.

EXAMPLES
    tf
        Apaga la pc.
\end{verbatim}

\subsubsection{restart}
\begin{verbatim}
NAME
    restart - Reincia la PC.

SYNOPSIS
    restart

DESCRIPTION
    restart reinicia la pc.

EXAMPLES
    restart
        Reincia la PC.
\end{verbatim}

\subsubsection{exit}
\begin{verbatim}
NAME
    exit - Cierra la shell.

SYNOPSIS
    exit

DESCRIPTION
    exit cierra la shell y si no existen otras reinicia el sistema.

EXAMPLES
    exit
        Reincia la pc.
\end{verbatim}

\newpage



\section{Código Fuente}

%makeSrcLatex
%makeIncLatex

\end{document}
